﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Xml;

namespace Amf4Asmx.Web.Handlers
{
    public class AmfReflectionHandler : IHttpHandler
    {
        #region IHttpHandler Members

        public bool IsReusable
        {
            get { return true; }
        }

        public void ProcessRequest(HttpContext context)
        {
            WebServiceData ws = ServiceUtils.GetWebServiceData(context, context.Request.FilePath);
            context.Response.ContentType = "text/xml";

            XmlTextWriter writer = new XmlTextWriter(context.Response.OutputStream, context.Response.ContentEncoding);
            writer.WriteStartDocument();
            writer.WriteStartElement("amf");

            writer.WriteStartElement("headers");
            foreach (KeyValuePair<string, System.Reflection.PropertyInfo> header in ws.SoapHeaders)
            {
                writer.WriteStartElement("header");
                writer.WriteAttributeString("name", header.Key);

                WriteType(writer, header.Value.PropertyType);

                writer.WriteEndElement();
            }
            writer.WriteEndElement();

            writer.WriteStartElement("methods");
            foreach (KeyValuePair<string, WebMethodData> method in ws.WebMethods)
            {
                writer.WriteStartElement("method");
                writer.WriteAttributeString("name", method.Key);

                writer.WriteStartElement("headers");
                writer.WriteAttributeString("direction", "in");
                foreach (string headerName in method.Value.InSoapHeaders)
                {
                    writer.WriteStartElement("header");
                    writer.WriteAttributeString("name", headerName);
                    writer.WriteEndElement();
                }
                writer.WriteEndElement();

                writer.WriteStartElement("headers");
                writer.WriteAttributeString("direction", "out");
                foreach (string headerName in method.Value.OutSoapHeaders)
                {
                    writer.WriteStartElement("header");
                    writer.WriteAttributeString("name", headerName);
                    writer.WriteEndElement();
                }
                writer.WriteEndElement();

                writer.WriteStartElement("parameters");
                foreach (System.Reflection.ParameterInfo pi in method.Value.Parameters)
                {
                    writer.WriteStartElement("parameter");
                    writer.WriteAttributeString("name", pi.Name);
                    WriteType(writer, pi.ParameterType);
                    writer.WriteEndElement();
                }
                writer.WriteEndElement();

                writer.WriteEndElement();
            }
            
            writer.WriteEndElement();

            writer.WriteEndElement();
            writer.Flush();
        }

        private void WriteType(XmlTextWriter writer, Type type)
        {
            if (type.IsEnum)
            {
                writer.WriteStartElement("enum"); // TODO
                foreach (Enum e in Enum.GetValues(type))
                {
                    writer.WriteStartElement("value");
                    writer.WriteAttributeString("name", e.ToString());
                    writer.WriteEndElement();
                }
                writer.WriteEndElement();
            }
            else if (typeof(System.Xml.XmlNode).IsAssignableFrom(type))
            {
                writer.WriteStartElement("xml"); 
                writer.WriteEndElement();
            }
            else if (type.IsArray)
            {
                writer.WriteStartElement("array");
                WriteType(writer, type.GetElementType());
                writer.WriteEndElement();
            }
            else if (type == typeof(string) || type.IsPrimitive)
            {
                writer.WriteStartElement("primitive");
                writer.WriteAttributeString("type", type.Name);
                writer.WriteEndElement();
            }
            else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                writer.WriteStartElement("null");
                writer.WriteEndElement();
                WriteType(writer, type.GetGenericArguments()[0]);
            }
            else
            {
                if (type.IsClass)
                {
                    writer.WriteStartElement("null");
                    writer.WriteEndElement();
                }
                foreach (System.Reflection.MemberInfo m in type.GetMembers())
                {
                    if (m is System.Reflection.FieldInfo)
                    {
                        writer.WriteStartElement("member");
                        writer.WriteAttributeString("name", m.Name);
                        writer.WriteAttributeString("set", "true");
                        writer.WriteAttributeString("get", "true");
                        WriteType(writer, (m as System.Reflection.FieldInfo).FieldType);
                        writer.WriteEndElement();
                    }
                    else if (m is System.Reflection.PropertyInfo)
                    {
                        writer.WriteStartElement("member");
                        writer.WriteAttributeString("name", m.Name);
                        writer.WriteAttributeString("set", ((m as System.Reflection.PropertyInfo).GetSetMethod() != null).ToString().ToLower());
                        writer.WriteAttributeString("get", ((m as System.Reflection.PropertyInfo).GetGetMethod() != null).ToString().ToLower());
                        WriteType(writer, (m as System.Reflection.PropertyInfo).PropertyType);
                        writer.WriteEndElement();
                    }
                }
            }
        }

        #endregion
    }
}
